const session = require('koa-session');
const axios = require('axios');
const sessionDb = require('../utils/sessionDb');
const config = require('../../config/index');
const { genUserTicket } = require('./user');

function register(app) {
  // const sessionDb = new SessionDb();
  const { appName } = process.env;

  const CONFIG = {
    key: 'koa.sess' /** (string) cookie key (default is koa.sess) */,
    maxAge: 86400000,
    httpOnly: true,
    signed: false,

    store: {
      async get(key) {
        const sessionKey = `session.${key}`;
        const sess = sessionDb.get(sessionKey)?.value();
        return sess;
      },
      async set(key, sess, maxAge, { rolling, changed }) {
        if (!rolling && !changed) return sess;
        const sessionKey = `session.${key}`;
        sessionDb.set(sessionKey, sess).write();

        // 更新 user session key list
        if (sess?.user?.id) {
          const userSessionKey = `user.${sess.user.id}`;
          const userSessList = sessionDb.get(userSessionKey).value() || [];

          userSessList.push(key);
          sessionDb.set(userSessionKey, userSessList).write();
        }

        return sess;
      },
      async destroy(key) {
        const sessionKey = `session.${key}`;

        const sess = sessionDb.get(sessionKey).value();
        // destroy key from session key list
        if (sess?.user?.id) {
          const userSessionKey = `user.${sess.user.id}`;
          let userSessList = sessionDb.get(userSessionKey).value() || [];

          userSessList = userSessList.filter(item => item !== key);

          if (!userSessList.length) {
            sessionDb.unset(userSessionKey).write();
          } else {
            sessionDb.set(userSessionKey, userSessList).write();
          }
        }

        sessionDb.unset(sessionKey).write();

        return true;
      },
    },
  };

  if (appName) {
    CONFIG.key = `koa.sess${appName}`;
  }

  app.use(session(CONFIG, app));
}

async function clearUserSession(uid) {
  console.log(`${process.env.appName}清理所有 user session`, uid);
  // const sessionDb = new SessionDb();
  const { appName } = process.env;

  const userSessionKey = `user.${uid}`;
  const userSessList = sessionDb.get(userSessionKey).value() || [];

  if (!userSessList.length) return true;

  userSessList.forEach(key => {
    const sessionKey = `session.${key}`;

    sessionDb.unset(sessionKey).write();
  });

  sessionDb.unset(userSessionKey).write();

  if (appName !== 'sso') return true;

  // SSO 通知其他应用清空当前用户的局部 session
  const subAppNames = Object.keys(config).filter(item => item !== 'sso');

  try {
    subAppNames.forEach(subAppName => {
      notifyClearSession(uid, subAppName);
    });
  } catch (error) {
    console.log(error);
  }

  return true;
}

function notifyClearSession(uid, appName) {
  if (!uid || !appName) return { error: 1, message: '参数错误' };

  console.log(`${process.env.appName}：通知 ${appName} 清理 ${uid} session`);
  const options = {
    method: 'get',
    baseURL: `http://${config[appName].host}:${config[appName].PORT}`,
    url: '/auth/logout',
    params: {
      uid,
      ticket: genUserTicket(uid, 'signout'),
    },
    responseType: 'json',
  };

  return axios(options)
    .then(res => {
      console.log(`${process.env.appName}：通知 ${appName} 清理 ${uid} session 成功`);
      return res.data;
    })
    .catch(() => {
      console.log(`${process.env.appName}：通知 ${appName} 清理 ${uid} session失败`);
      return {
        error: 1,
        message: `${process.env.appName}：通知 ${appName} 清理 ${uid} session失败`,
      };
    });
}

module.exports = {
  register,
  clearUserSession,
  notifyClearSession,
};
